#! /usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os
import shutil
import zipfile
import subprocess
import conf
import pycurl
import StringIO
import json
import time

def zip_folder(files_folder, out_path, zip_filename):
    cwd = files_folder
    start = cwd.rfind(os.sep) + 1
    z = zipfile.ZipFile(out_path + zip_filename, mode="w", compression=zipfile.ZIP_DEFLATED)
    try:
        for dirpath, dirs, files in os.walk(cwd):
            for file in files:
                z_path = os.path.join(dirpath, file)
                z.write(z_path, z_path[start:])
        z.close()
    finally:
        if z:
            z.close()

def unzip(file_name, ex_path):
    file_zip = zipfile.ZipFile(file_name, 'r')
    file_names = file_zip.namelist()
    for file in file_names:
        file_zip.extract(file, ex_path)
    file_zip.close() 
    return file_names

def download_patch(url, branch_name):
    zipfile = conf.outSourceDir + branch_name + '.zip';
    if os.path.exists(zipfile):
        os.remove(zipfile)
    c = pycurl.Curl()
    c.setopt(pycurl.FOLLOWLOCATION, 1) #允许跟踪来源
    c.setopt(pycurl.MAXREDIRS, 5)
    head = ['Accept:*/*','User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0']
    buf = StringIO.StringIO()
    c.setopt(pycurl.WRITEFUNCTION, buf.write)
    c.setopt(pycurl.URL, url)
    c.setopt(pycurl.HTTPHEADER,  head)
    c.perform()
    the_page =buf.getvalue()
    buf.close()
    f = open(zipfile, 'wb')
    f.write(the_page)
    f.close()

def make_patch(branch_name):

    print '补丁制作中...'

    # 根据分支名得到tag名称
    tag = branch_name.split('-')[0]

    # 源码目录，补丁目录
    source_dir = conf.originSourceDir
    out_path = conf.outSourceDir
    patch_dir = conf.outSourceDir + branch_name + os.sep
    # print '补丁目录' + patch_dir
    origin_name = conf.originName

    # 判断仓库是否存在，不存在则创建
    if not os.path.exists(source_dir):
        print '仓库初始化中...'
        os.popen('git clone ' + conf.originUrl + ' ' + source_dir)
        print '仓库初始化成功'

    if os.path.exists(patch_dir):
        shutil.rmtree(patch_dir)

    os.makedirs(patch_dir)
    git_fetch_command = 'git fetch ' + origin_name
    
    # 进入源码目录
    os.chdir(source_dir)

    # 更新仓库
    os.popen(git_fetch_command)
    print '仓库更新成功...'

    # 判断tag是否存在
    tag_exists = os.popen("git tag -l '" + tag + "'")
    tag_name = tag_exists.read().strip('\n')
    if not tag_name:
        print 'tag:' + tag + ' 不存在, 请检查分支名称.'
        sys.exit()

    # 切换到补丁分支
    print "切换到分支" + branch_name
    os.popen("git checkout -b " + branch_name + " " + origin_name + "/" + branch_name);
    print "分支切换成功"
    
    diff = os.popen("git diff " + branch_name + " " + tag + "  --name-only")
    for file in diff.readlines():
        file = file.strip('\n')
        # print source_dir + file
        if os.path.isfile(source_dir + file):
            if not os.path.exists(os.path.dirname(patch_dir + file)):
                os.makedirs(os.path.dirname(patch_dir + file))
            shutil.copy(source_dir + file, patch_dir + file)
    diff.close();

    print "文件拷贝成功"
    zip_folder(patch_dir, out_path, branch_name + '.zip')
    print "补丁包制作成功"
    
    # TODO 上传到远程服务器
    storage = StringIO.StringIO()
    c = pycurl.Curl();
    c.setopt(c.URL, conf.uploadUrl)
    c.setopt(c.WRITEFUNCTION, storage.write)
    values = [('file', (c.FORM_FILE, out_path + branch_name + '.zip')),('signkey', conf.signkey)]
    c.setopt(c.HTTPPOST, values)
    c.perform()
    c.close()
    html = storage.getvalue()
    decodejson = json.loads(html)
    if not decodejson['status']:
        print "补丁上传失败 " + decodejson['msg']
    else:
        print "补丁包上传成功"
    
    # 删除分支
    os.popen("git checkout master")
    os.popen("git branch -D " + branch_name)
    # 删除补丁目录
    shutil.rmtree(patch_dir)
    os.remove(out_path + branch_name + '.zip')
    print "分支及目录清理成功"
    print "补丁制作完成"
    sys.exit()

def install_patch(branch_name, force):
    # 根据分支名得到tag名称
    tag = branch_name.split('-')[0]
    # 获取客户机版本
    mdfp = open(conf.workingDir + 'README.md', 'r')
    readme = mdfp.readlines()
    mdfp.close()
    if len(readme) < 2:
        print '客户版本号未知, 请检查 ' + conf.workingDir + 'README.md'
        sys.exit()
    user_version = readme[1].strip('\n')
    if user_version != tag:
        print '此补丁包不适用与客户系统版本, 客户系统版本号为: ' + user_version
        sys.exit()
    
    print '补丁包获取中...'
    
    url = conf.downloadUrl + tag + '/' + branch_name + '.zip'

    # 下载并文件
    download_patch(url, branch_name)
    # 解压文件
    zipfile = conf.outSourceDir + branch_name + '.zip';
    files = unzip(zipfile, conf.outSourceDir + branch_name)
    print "补丁包下载成功"

    ## 检查文件是否已经被修改过
    fp = open(conf.backupDir + 'patchfile.log', 'r')
    log_file = fp.readlines()
    # 去掉文件的换行符，建议一个新数组
    chk = []
    for lf in log_file:
        chk.append(lf.strip('\n'))
    fp.close()
    # 查询两个数据的交集
    repeatfile = list(set(files).intersection(set(chk)))
    if len(repeatfile) > 0 and not force:
        print '补丁包文件冲突,冲突文件如下:'
        for repeat in repeatfile:
            print '- ' + repeat
        print '请基于修改过的文件重新创建补丁包...'
        sys.exit()

    time_str = time.strftime('%Y%m%d',time.localtime(time.time()))
    patchDir = conf.outSourceDir + branch_name + os.sep
    workingDir = conf.workingDir
    backupFile = time_str + '-' + branch_name
    backupDir = conf.backupDir + backupFile + os.sep
    if os.path.exists(backupDir):
        shutil.rmtree(backupDir)
    # 获取文件列表
    fps = open(conf.backupDir + 'patchfile.log', 'w')
    for file in files:
        if os.path.isfile(workingDir + file):
            # 备份文件
            # 目录不存在则创建
            if not os.path.exists(os.path.dirname(backupDir + file)):
                os.makedirs(os.path.dirname(backupDir + file))
            # 复制文件
            shutil.copy(workingDir + file, backupDir + file)
            # 覆盖文件
            # 目录不存在则创建
            if not os.path.exists(os.path.dirname(workingDir + file)):
                os.makedirs(os.path.dirname(workingDir + file))
            # 复制文件
            shutil.copy(patchDir + file, workingDir + file)
            # 加入日志文件
            fps.write(file + '\n')
    fps.close()

    # 压缩备份目录
    zip_folder(backupDir, conf.backupDir, backupFile + '.zip')
    # 清理备份目录, 补丁目录
    shutil.rmtree(backupDir)
    shutil.rmtree(conf.outSourceDir + branch_name)
    os.remove(zipfile)
    print '补丁安装成功'
    sys.exit()

def uninstall_patch(branch_name):
    print '补丁卸载中...'
    time_str = time.strftime('%Y%m%d',time.localtime(time.time()))
    workingDir = conf.workingDir
    backupFile = time_str + '-' + branch_name
    zipfile = conf.backupDir + backupFile + '.zip'
    if not os.path.exists(zipfile):
        print '备份文件不存在'
    else:
        # 解压备份压缩
        files = unzip(zipfile, conf.backupDir + branch_name)
        for file in files:
            shutil.copy(conf.backupDir + branch_name + os.sep+ file, workingDir + file)
        # 去掉日志文件记录
        fp = open(conf.backupDir + 'patchfile.log', 'r')
        log_file = fp.readlines()
        # 去掉文件的换行符，建议一个新数组
        chk = []
        for lf in log_file:
            chk.append(lf.strip('\n'))
        fp.close()
        new_log = list(set(chk).difference(set(files)))
        fps = open(conf.backupDir + 'patchfile.log', 'w')
        for log in new_log:
            fps.write(log + '\n')
        fps.close()
    print '补丁卸载成功'
    sys.exit()

if len(sys.argv) < 3 :
    print 'usage: patch.py\t create \tCreate Patch'
    print '\t\t install \tInstall Patch'
    print '\t\t forceinstall \tForce Install Patch'
    print '\t\t uninstall \tUninstall Patch'
    sys.exit()

action=sys.argv[1]
branch=sys.argv[2]
if action == 'create' :
    make_patch(branch)
elif action == 'install' :
    install_patch(branch, False)
elif action == 'forceinstall' :
    install_patch(branch, True)
elif action == 'uninstall' :
    uninstall_patch(branch)
else :
    print 'usage: patch.py\t create \tCreate Patch'
    print '\t\t install \tInstall Patch'
    print '\t\t forceinstall \tForce Install Patch'
    print '\t\t uninstall \tUninstall Patch'
    sys.exit()